package com.simple.gateway.core.network.handlers;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.simple.gateway.common.interfaces.GatewayAuth;
import com.simple.gateway.common.spi.ExtensionLoader;
import com.simple.gateway.core.mapping.HttpStatement;
import com.simple.gateway.core.network.BaseHandler;
import com.simple.gateway.core.network.util.AgreementConstants;
import com.simple.gateway.core.network.util.GatewayResultMessage;
import com.simple.gateway.core.network.util.ResponseParser;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

/**
 * 项目: simple-gateway
 * <p>
 * 功能描述: 鉴权的handler
 *
 * @author: WuChengXing
 * @create: 2023-08-06 15:41
 **/
public class AuthorizationHandler extends BaseHandler<FullHttpRequest> {

    private final Logger logger = LoggerFactory.getLogger(AuthorizationHandler.class);

    /**
     * {@link com.simple.gateway.common.constant.enums.AuthType}
     */
    @Override
    protected void session(ChannelHandlerContext ctx, Channel channel, FullHttpRequest request) {
        logger.info("网关接收请求【鉴权】 uri：{} method：{}", request.uri(), request.method());
        try {
            HttpStatement httpStatement = channel.attr(AgreementConstants.HTTP_STATEMENT).get();
            if (httpStatement.isAuth()) {
                // 获取请求头
                HttpHeaders headers = request.headers();
                String authExtension = headers.get("auth_extension");
                JSONObject jsonObject = JSON.parseObject(authExtension);
                String authType = (String) jsonObject.get("auth_type");
                // 授权类型，如用户自定义则需要定义方告诉接口调用者
                DefaultFullHttpResponse checkAuthType = checkAuthType(authType);
                // 校验授权类型是否符合
                if (Objects.nonNull(checkAuthType)) {
                    channel.writeAndFlush(checkAuthType);
                }
                GatewayAuth auth = ExtensionLoader.getLoader(GatewayAuth.class).getExtension(authType);
                try {
                    // 授权相关参数，用户自定义
                    boolean status = auth.validate(authExtension);
                    // 鉴权成功；直接放行
                    if (status) {
                        request.retain();
                        ctx.fireChannelRead(request);
                    }
                    // 鉴权失败
                    else {
                        DefaultFullHttpResponse response = new ResponseParser()
                                .parse(GatewayResultMessage.buildError(AgreementConstants.ResponseCode._403.getCode(),
                                        "对不起，你无权访问此接口！"));
                        channel.writeAndFlush(response);
                    }
                } catch (Exception e) {
                    DefaultFullHttpResponse response = new ResponseParser()
                            .parse(GatewayResultMessage.buildError(AgreementConstants.ResponseCode._403.getCode(),
                                    "对不起，你的鉴权不合法！"));
                    channel.writeAndFlush(response);
                }
            }
            // 不鉴权放行
            else {
                request.retain();
                ctx.fireChannelRead(request);
            }
        } catch (Exception e) {
            // 4. 封装返回结果
            DefaultFullHttpResponse response = new ResponseParser()
                    .parse(GatewayResultMessage.buildError(AgreementConstants.ResponseCode._500.getCode(),
                            "网关协议调用失败！" + e.getMessage()));
            channel.writeAndFlush(response);
        }
    }

    private DefaultFullHttpResponse checkAuthType(String authType) {
        DefaultFullHttpResponse response = null;
        if (StrUtil.isEmpty(authType)) {
            response = new ResponseParser()
                    .parse(GatewayResultMessage
                            .buildError(AgreementConstants.ResponseCode._400.getCode(),
                                    "请检查用户信息上是否配置auth_type !！"));
        }
        return response;
    }
}
